from flask import Flask, render_template, request, jsonify, redirect, session, make_response
import loguru
from captcha.image import ImageCaptcha
import random
import os

from langchain_core.messages import HumanMessage, AIMessage
from sqlalchemy import inspect

from RAG.RAGBuild import get_user_input_names_by_user_id, delete_kb_by_user_id
from models import db
from models.user import User
from models.role import Role
from models.chat_session import ChatSession
from models.user_role import UserRole
from models_function.user_function import *
from models_function.role_function import *
from models_function.chat_session_function import *
from models_function.user_role_function import *
from multi_modal import chat_with_user, generate_image
from multi_modal.audio_to_text import audio_to_text
from multi_modal.public import view_chat_history, clear_history
from qq_email import QQMailSender, ValidateEmail
from he_lib_group_tools import Config
from RAG import *
from image_analysis import ImageAnalysis
from multi_modal.public import get_history

import time

"""全局配置区域"""
# --------------config--------------
config = Config(config_file="config/config.json")
# --------------日志记录器--------------
logger = loguru.logger
# 确保日志文件保存在项目根目录下的log文件夹中，日志文件名以日期命名
logger.add("log/file_{time:YYYY-MM-DD}.log", rotation="1 day")
# --------------app相关设置--------------
# 创建一个app
app = Flask(__name__)
# 设置session的密钥
app.secret_key = "malegebideuabiflaskbushipwlinuxma"
# --------------数据库相关--------------
# 配置数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = config.get_required("SQLALCHEMY_DATABASE_URI")
logger.info(f"数据库连接已启动:{app.config['SQLALCHEMY_DATABASE_URI']}")
# 初始化db
db.init_app(app)
with app.app_context():
    logger.info("测试进入app.app_context()")
    inspector = inspect(db.engine)
    if 'users' not in inspector.get_table_names():
        db.create_all()

    list1 = add_default_roles()
    for li in list1:
        logger.info(li.to_dict())

# --------------邮件发送相关--------------
qq_email_user = config.get_required("qq_email")["email_address"]
qq_email_password = config.get_required("qq_email")["email_password"]
logger.debug(f"QQ邮箱账号:{qq_email_user},{qq_email_password}")
qq_mail_sender = QQMailSender(user=qq_email_user,
                              password=qq_email_password)
# logger.info(f"邮件发送器已启动:email_address:{qq_mail_sender.user}\temail_password:{qq_mail_sender.password}")
# 邮箱验证
validate_email = ValidateEmail()
# --------------RAG相关--------------
# 获取RAG包的配置
RAG_config = config.get_required("RAG")
# 获取RAGBuild配置
RAGBuild_config = RAG_config["RAGBuild"]
# 初始化 RAG 构建器
rag_build = RAGBuild(
    redis_url=RAGBuild_config["redis_url"],
    embedding_model_name=RAGBuild_config["embedding_model_name"],
    embedding_model_api_key=RAGBuild_config["embedding_model_api_key"]
)
logger.debug("初始化 RAGBuild 成功")
# 获取RAGChatter配置
RAGChatter_config = RAG_config["RAGChatter"]
# 初始化 RAGChatter 并传入 retriever
rag_chatter = RAGChatter(
    api_base_url=RAGChatter_config["api_base_url"],
    api_key=RAGChatter_config["api_key"],
    redis_url=RAGChatter_config["redis_url"],
    temperature=RAGChatter_config["temperature"],
    rag_build=rag_build
)
# --------------图片处理--------------------
UPLOAD_FOLDER = config.get_required("UPLOAD_FOLDER")
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
# 配置上传文件的存储路径，供后续文件操作使用，类型为字符串（str）
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
image_analysis_upload_folder = app.config['UPLOAD_FOLDER']
# 获取图片识别参数
ImageAnalysis_config = config.get_required("image_analysis")["ImageAnalysis"]
image_analysis = ImageAnalysis(
    model_name=ImageAnalysis_config["model_name"],
    api_key=ImageAnalysis_config["api_key"],
    base_url=ImageAnalysis_config["base_url"]
)
# ----------------音频转文字部分---------------------
AudioToText_config = config.get_required("multi_modal")["audio_to_text"]
audio_to_text_relative_audio_path = AudioToText_config["relative_audio_path"]
"""路由区域"""


# ------------------------------主页相关------------------------------
# 对主页进行渲染
@app.route('/')
def home():
    return render_template('home.html')


@app.route('/product_features')
def product_features():
    return render_template('product_features.html')


# ------------------------------验证码------------------------------
@app.route("/captcha")
def generate_captcha():
    # 生成4位随机字符（可自定义字符集）,去掉了I和1防止混淆难以辨别
    captcha_text = ''.join(random.choices('ABCDEFGHJKLMNPQRSTUVWXYZ23456789', k=4))
    session['captcha'] = captcha_text  # 存储到session
    logger.info(f"生成验证码:{captcha_text}")
    # 生成验证码图像
    image = ImageCaptcha(width=120, height=60)
    img_bytes = image.generate(captcha_text)

    # 返回图像响应
    return make_response(img_bytes.getvalue(), 200, {
        'Content-Type': 'image/png',
        'Cache-Control': 'no-cache'
    })


# -------------------------------验证邮箱是否已经注册----------------------------------
@app.route('/verify_user_mail_has_been_registered', methods=['POST'])
def verify_user_mail_has_been_registered():
    logger.debug("verify_user_mail_has_been_registered")
    data = request.get_json()
    if not data or 'user_mail' not in data:
        return jsonify({'message': '缺少参数'}), 400
    user_mail = data.get('user_mail')
    logger.debug(f"verify_user_mail_has_been_registered: {user_mail}")

    # 根据前端发过来的邮箱去数据库中查找是否有这个用户
    user_id = get_id_by_mail(user_mail)
    if user_id:
        return jsonify({'success': False, 'message': '邮箱已注册'}), 200  # 明确返回success: False
    else:
        return jsonify({'success': True, 'message': '邮箱未注册'}), 200


# ------------------------------登录相关------------------------------
# 对登录页面进行渲染
@app.route('/login')
def login():
    if session.get('user_id') and session.get('role') == 'user':
        return redirect('/chat_page')
    if session.get('user_id') and session.get('role') == 'admin':
        return redirect('/admin')
    return render_template('login.html')


# 处理用户登录的路由
@app.route('/login_process', methods=['POST'])
def login_process():
    user_mail = request.form.get('user_mail')
    password = request.form.get('user_password')
    user = login_user(user_mail, password)
    logger.debug(f"用户登录:{user_mail}\t{password} user对象为:{user}")
    # 如果用户输入的和session中存的验证码一致，则登录成功,否则就返回错误页面
    user_input = request.form.get("captcha", "").upper()
    if user_input != session.get("captcha", ""):
        logger.error("验证码错误")
        return redirect('/login')
    if user:
        session['user_id'] = user.user_id
        user_role_login = find_user_role_by_user_id(user_id=user.user_id)
        if user_role_login:
            logger.debug(f"user_role:{user_role_login}判断user_role的类型为:{type(user_role_login)}")
            # 1是admin,2是普通用户
            if user_role_login.role_id == 1:
                session['role'] = "admin"
                return redirect('/admin')
            session['role'] = "user"
            session['user_name'] = find_user_by_id(get_id_by_mail(user_mail)).user_name
            session['user_mail'] = user_mail
            logger.debug(f"用户登录成功:{user_mail}\t{password}")
            return redirect('/chat_page')
        else:
            logger.debug(f"用户登录失败:{user_mail}\t{password}")
        return redirect('/login')
    else:  # 如果没有登录成功则返回登录页面
        logger.debug("用户对象为空--登录失败")
        return redirect('/login')


@app.route('/logout', methods=['GET', 'POST'])
def logout():
    session.pop('user_mail', None)
    session.pop('role', None)
    session.pop('user_id', None)
    return redirect('/login')


@app.route('/user_info', methods=['GET', 'POST'])
def user_info():
    logger.debug(f"user info:{session.get('user_name')} \t {session.get('user_mail')}")
    return jsonify({
        'user_name': session.get('user_name'),
        'user_mail': session.get('user_mail')
    })


# --------------------------------忘记密码-----------------------------
@app.route('/forget_password')
def forget_password():
    if session.get('user_id'):
        return redirect('/chat')
    return render_template('forget_password.html')


@app.route('/forget_password_process', methods=['POST'])
def forget_password_process():
    data = request.get_json()  # 获取 JSON 数据

    user_mail = data.get('user_mail')
    if not user_mail:
        logger.debug("用户邮箱为空--忘记密码失败")
    session["user_mail"] = user_mail

    mail_captcha = data.get('mail_captcha')
    if mail_captcha != session.get('mail_captcha'):
        logger.debug("验证码错误--忘记密码失败")
        return redirect('/forget_password')

    session["token"] = user_mail + mail_captcha

    # 如果用户输入的和session中存的验证码一致，则登录成功,否则就返回错误页面
    user_input = data.get('captcha').upper()
    if user_input != session.get("captcha", ""):
        logger.debug("验证码错误")
        return redirect('/forget_password')
    return jsonify({
        "success": "验证码正确",
        "token": user_mail + mail_captcha
    })


# 向邮箱发送验证码

@app.route('/send_captcha_to_email', methods=['POST'])
def send_captcha_to_email():
    data = request.get_json()  # 获取 JSON 数据
    user_mail = data.get("user_mail", "")
    logger.debug(f"发送验证码到邮箱: {user_mail}")
    if not user_mail:
        return jsonify({
            "message": "user_mail为空"
        })
    mail_captcha = ''.join(random.choices('ABCDEFGHJKLMNPQRSTUVWXYZ23456789', k=4))
    session['mail_captcha'] = mail_captcha
    result = qq_mail_sender.send(
        to=user_mail,
        subject='验证码:',
        contents=[
            f"验证码: {mail_captcha}"
        ]
    )
    logger.debug(result)
    return jsonify({
        "success": True,
        "message": "验证码已发送"
    })


# ------------------------------修改密码------------------------------
@app.route('/reset_password/<token>')
def reset_password(token):
    if session.get('user_id'):
        return redirect('/chat')
    if not token or token != session.get('token'):
        return redirect('/forget_password')
    return render_template('reset_password.html')


@app.route('/reset_password_process', methods=['POST'])
def reset_password_process():
    data = request.get_json()  # 获取 JSON 数据
    new_password = data.get('new_password')
    token = data['token']
    user_id = get_id_by_mail(session.get('user_mail'))
    if user_id is None:
        return jsonify({'message': '根据邮箱查找用户,但是没找到'})
    user = find_user_by_id(user_id)
    if user is None:
        return jsonify({
            "message": "查询不到用户信息"
        })
    user = update_user(user_id=user_id, user_name=user.user_name, user_password=new_password, user_mail=user.user_mail)
    if user:
        return jsonify({
            "success": True,
            "message": "密码重置成功"
        })
    return jsonify({
        "message": "密码重置失败"
    })


# ------------------------------注册相关------------------------------
# 对注册页面进行渲染
@app.route('/register')
def register():
    if session.get('user_id') and session.get('role') == 'user':
        return redirect('/chat_page')
    if session.get('user_id') and session.get('role') == 'user':
        return redirect('/admin')
    return render_template('register.html')


# 处理用户注册的路由
@app.route('/register_process', methods=['POST'])
def register_process():
    data = request.get_json()  # 获取 JSON 数据
    # new_password = data.get('new_password')
    user_mail = data.get('user_mail')
    user_name = data.get('user_name')
    user_password = data.get('user_password')
    # 验证码验证
    if session.get('mail_captcha') != data.get('mail_captcha'):
        logger.debug(f"邮箱验证码错误{session.get('mail_captcha')}\t{data.get('mail_captcha')}")
        return jsonify({
            "message": "邮箱验证码错误",
        })
    # 如果用户输入的和session中存的验证码一致，则登录成功,否则就返回错误页面
    user_input = data.get("captcha", "").upper()
    if user_input != session.get("captcha", ""):
        logger.debug("验证码错误")
        return redirect('/register')
    logger.debug(f"用户注册:{user_mail}\t{user_name}\t{user_password}")
    # 验证邮箱是否可用
    result = validate_email.get_result(user_mail)
    # 检查邮箱格式
    if not result.get('format'):
        return jsonify({"message": "邮箱格式错误"})

    # 检查域名有效性
    if not result.get('dns'):
        return jsonify({"message": "邮箱域名不存在"})
    user = add_user(user_mail=user_mail, user_password=user_password, user_name=user_name)
    logger.debug(f"用户id:{user.user_id}")
    user_role_register = add_user_role(user_id=user.user_id, role_id=2)
    if user_role_register and user:
        logger.debug(
            f"用户角色添加成功:user_role对象:{user_role_register}\trole:{user_role_register.role_id}\tuser:{user_role_register.user_id}")
        return jsonify({
            "success": True,
            "message": "用户注册成功",
        })
    else:
        logger.debug(f"用户角色添加失败:user_role:{user_role_register}")
        return jsonify({
            "message": "用户添加失败",
        })


# ------------------------------chat相关------------------------------
# ------------------------------RAGchat相关------------------------------
@app.route('/chat_rag_page')
def chat_rag_page():
    if not session.get('user_id'):
        return redirect('/login')
    return render_template('chat_rag.html')


# 修改 switch_conversation 路由，确保设置检索器
@app.route('/chat_rag/switch_conversation/', methods=['GET'])
def chat_rag_switch_conversation():
    chat_id = request.args.get("id")
    knowledge_base_name = request.args.get("kb")

    logger.debug(f"chat_id:{chat_id}\tknowledge_base_name:{knowledge_base_name}")

    # 验证参数
    if not chat_id or not knowledge_base_name:
        return jsonify({"error": "Missing parameters"}), 400

    # 保存到session
    session["chat_id"] = int(chat_id)
    session["knowledge_base_name"] = knowledge_base_name

    return jsonify(rag_chatter.view_chat_history(
        user_id=session.get('user_id'),
        session_id=int(chat_id)
    ))


@app.route('/chat_rag/delete_conversation/', methods=['GET'])
def chat_rag_delete_conversation():
    chat_id = request.args.get("id")
    knowledge_base_name = request.args.get("kb")

    logger.debug(f"chat_id:{chat_id}\tknowledge_base_name:{knowledge_base_name}")

    # 验证参数
    if not chat_id or not knowledge_base_name:
        return jsonify({"error": "Missing parameters"}), 400

    # 删除对话历史记录
    rag_chatter.clear_history(user_id=session.get('user_id'), chat_id=int(chat_id))
    if not delete_chat_session(user_id=session.get('user_id'), chat_id=int(chat_id)):
        return jsonify({"error": "Missing parameters"}), 400
    # 保存到session
    session["chat_id"] = int(chat_id)
    session["knowledge_base_name"] = knowledge_base_name

    return jsonify(rag_chatter.view_chat_history(
        user_id=session.get('user_id'),
        session_id=int(chat_id)
    ))


# 实现删除知识库功能
@app.route('/chat_rag/delete_knowledge_base', methods=['POST'])
def chat_rag_delete_knowledge_base():
    data = request.get_json()
    kb_name = data.get("kb_name")

    if not kb_name:
        return jsonify({"error": "Missing knowledge base name"}), 400

    # 删除Redis中的索引
    index_name = get_index_name(
        user_id=session.get('user_id'),
        user_input_name=kb_name
    )

    try:
        if not delete_kb_by_user_id(redis_url=RAGBuild_config["redis_url"], user_id=session.get('user_id'),
                                    kb_name=kb_name):
            return jsonify({"error": "Failed to delete knowledge base"}), 500

        # 如果删除的是当前使用的知识库，清空session
        if session.get("knowledge_base_name") == kb_name:
            session.pop("knowledge_base_name", None)

        return jsonify({"success": True})
    except Exception as e:
        logger.error(f"删除知识库失败: {str(e)}")
        return jsonify({"error": str(e)}), 500


@app.route('/chat_rag/build_knowledge_base', methods=['POST'])
def chat_rag_build_knowledge_base():
    kb_name = request.form.get('kb_name')
    files = request.files.getlist('files')
    logger.debug(f"接收到构建知识库请求，知识库名称：{kb_name}，文件列表：{files}")
    if not kb_name or not files:
        return jsonify({"error": "Missing knowledge base name or files"}), 400
    logger.debug(f"user_id is {session.get('user_id')}")
    redis_vector_store = rag_build.fast_build_faq(
        user_id=session.get("user_id"),
        faq_name=kb_name,
        files=files,
        files_name=[file.filename for file in files]
    )
    if not redis_vector_store:
        logger.debug("创建知识库失败")
        return jsonify({"error": "Failed to build knowledge base"}), 500
    logger.debug(f"创建知识库: {kb_name} with {len(files)} files")

    return jsonify({
        "success": True,
        "message": f"Knowledge base '{kb_name}' built successfully"
    })


@app.route('/chat_rag/get_all_knowledge_base', methods=['POST', 'GET'])
def chat_rag_get_all_knowledge_base():
    index_names = get_user_input_names_by_user_id(redis_url=RAGBuild_config["redis_url"],
                                                  user_id=session.get("user_id"))
    logger.debug(f"获取{session.get('user_id')}用户所有知识库:{index_names}")
    session["index_names"] = str(index_names)
    logger.debug(f"session保存用户所有知识库:{session.get('index_names')}")
    return jsonify(index_names)


@app.route('/chat_rag/load_conversations', methods=['POST', 'GET'])
def chat_rag_load_conversations():
    user_id = session.get('user_id', 0)  # 假设用户已登录，从 session 获取 user_id
    user_chat_sessions = find_chat_sessions_by_user_id(user_id=user_id)
    if user_chat_sessions:
        logger.debug(f"用户会话列表:{user_chat_sessions}")
        """# 构建返回值
        [
          {
            "id": 1,
            "title": "新对话"
          },
          {
            "id": 2,
            "title": "关于AI的问题"
          }
        ]
        """
        ret_list: list[dict] = []
        for user_chat_session in user_chat_sessions:
            if user_chat_session.chat_type == "RAG":
                ret_list.append({
                    "id": user_chat_session.chat_id,
                    "title": user_chat_session.title
                })
        logger.debug(f"用户会话列表返回:{ret_list}")
        return jsonify(ret_list)
    return jsonify([])


#
# @app.route('/chat_rag/switch_conversation/', methods=['GET'])
# def chat_rag_switch_conversation():
#     chat_id = request.args.get("id")
#     if not chat_id:
#         return jsonify({"error": "Missing chat_id"}), 400
#
#     # 接受使用的知识库名称
#     knowledge_base_name = request.args.get("kb")
#     if not knowledge_base_name:
#         return jsonify({"error": "Missing knowledge_base_name"}), 400
#
#     # 将chat_id保存到session中，下次请求时使用
#     session["chat_id"] = int(chat_id)
#     session["knowledge_base_name"] = knowledge_base_name
#     # 这里的id就是chat_id也就是ai聊天模块中的session_id
#     return jsonify(rag_chatter.view_chat_history(user_id=session.get('user_id'), session_id=int(chat_id)))


@app.route('/chat_rag', methods=['POST', 'GET'])
def chat_rag():
    audio_text = None  # 初始化音频转文字结果变量

    need_create_new_conversation = True
    # 用户发送的消息在前端叫做 prompt
    user_msg = request.form.get("prompt")
    # 接受使用的知识库名称
    knowledge_base_name = request.form.get("selectedKnowledgeBase")
    logger.debug(f"用户{session.get('user_id')}选择的知识库名称:{knowledge_base_name}")
    if knowledge_base_name:
        tips = ""
    else:
        tips = "None_kb"
    # 构建index_name
    index_name = get_index_name(user_id=session.get('user_id'),
                                user_input_name=knowledge_base_name)
    logger.debug(f"构建的index_name:{index_name}")
    # 使用的模型名称在前端叫做 model
    model_name = request.form.get("model")
    # 看看是否需要文生图
    text2img = request.form.get("enable_txt2img")
    # 当前用户的会话id在前端叫做 conversation_id,在数据库操作中叫做chat_id,在模型使用模块叫做session_id
    chat_id = request.form.get("conversation_id")
    logger.debug(f"用户发送的消息:{user_msg}\t使用的模型名称:{model_name}\t当前用户的会话id:{chat_id}")
    # 这是前端发来的图片列表
    images = request.files.getlist("images")
    # ============音频转文字============
    # 获取前端发来的音频文件
    audio_files = request.files.getlist("audios")
    logger.debug(f"音频文件:{audio_files}")
    logger.debug(f"音频文件列表长度:{len(audio_files)}")
    if audio_files and len(audio_files) != 0:
        logger.debug(f"进入处理音频过程,如果不是上传的音频或者没有上传音频不应进入这里")

        try:
            # 计数器音频文件当前处理到第几个
            count_audio = 1
            audio_text = "以下是音频转录结果:"
            for audio in audio_files:
                audio_path = os.getcwd() + audio_to_text_relative_audio_path + str(
                    session.get('user_id')) + "/" + "audio_to_text/"
                logger.debug(f"audio_path:{audio_path}")
                # 如果audio目录不存在就创建
                if not os.path.exists(audio_path):
                    os.makedirs(audio_path)
                with open(audio_path + audio.filename, "wb") as f:
                    f.write(audio.read())
                logger.debug(f"处理音频文件路径:{audio_path + audio.filename}")
                audio_text += f"\n第{count_audio}个音频转录结果:"
                audio_text += audio_to_text(audio_path + audio.filename)
                count_audio += 1

        except Exception as e:
            logger.error(e)
        logger.debug(f"音频转录结果:{audio_text}")
    user_id = session.get('user_id', 0)
    # 如果没有从前端获取到chat_id(或者说获取到chat_id不是空)，则创建一个新的对话
    if chat_id:  # 表示有会话id,那么就不需要创建新的对话
        need_create_new_conversation = False
    # ============图片分析============
    image_ai_msg = str()
    if images and len(images) != 0:
        logger.debug(f"test image_name:{images[0].filename}")
        # 分析 图片
        image_ai_msg = image_analysis.analysis(images=images,
                                               upload_folder=image_analysis_upload_folder + "/" + str(
                                                   session.get('user_id')) + "/" + "image_analysis/")
        if image_ai_msg is None:
            logger.debug("图片分析失败")
            return jsonify({'error': '分析图片失败'}), 400
    # ===========聊天逻辑处理,需要区分为有chat_id(从以前的历史继续对话)没有chat_id(新创建的对话)============
    if need_create_new_conversation:
        # 当前没有对话,新加一个对话
        """
        这段代码的可读性有点差,特别注释一下,当前需要获取一个新的chat_id;
        但是对于数据中的操作来说,想要得到chat_id需要先创建一个chat_session;
        而创建一个chat_session需要chat_id,那么我们通过根据user_id找到其所有的chat_session,之后
        找到其中的chat_id的最大值+1,如果是空列表说明当前用户没有对话,就返回0,之后我将其+1
        将用户输入的前20个字符作为title
        """
        chat_session = add_chat_session(
            user_id=user_id,
            chat_id=get_max_chat_id(
                user_chat_sessions=find_chat_sessions_by_user_id(
                    user_id=user_id
                )
            ) + 1,
            title=user_msg[:20],
            chat_type="RAG"  # 用于和普通聊天的记录区分开
        )
        history_manager = rag_chatter.get_history(user_id=session.get('user_id'), chat_id=chat_session.chat_id)
        # ============音频识别返回结果============
        if audio_text:
            history_manager.add_message(HumanMessage(content=[file.filename for file in audio_files]))
            history_manager.add_message(AIMessage(content=audio_text))
            return jsonify({
                "response": audio_text,
                "conversation_id": chat_session.chat_id,
                "new_conversation_created": True
            })
        # ============文生图============
        if text2img and text2img == "true":
            generate_image_ret_dict = generate_image(user_msg)
            logger.debug(f"文生图结果:{generate_image_ret_dict}")
            history_manager.add_message(HumanMessage(content=user_msg))
            history_manager.add_message(AIMessage(content=str(generate_image_ret_dict)))
            return jsonify({
                "image_url": generate_image_ret_dict["image_url"],
                "response": generate_image_ret_dict["description"],
                "conversation_id": chat_session.chat_id,
                "new_conversation_created": True
            })
        ai_msg = rag_chatter.chat(
            user_id=user_id,
            chat_id=chat_session.chat_id,
            user_question=user_msg + image_ai_msg,
            chain=rag_chatter.create_chain(
                rag_build.get_embedding_retriever(
                    redis_vector_store=rag_build.get_redis_vector_store_by_index_name(index_name)
                )
            ),
        )
        session["chat_id"] = chat_session.chat_id
        return jsonify({
            "response": ai_msg,
            "conversation_id": chat_session.chat_id,
            "new_conversation_created": True,
            "tips": tips
        })
    else:
        history_manager = rag_chatter.get_history(user_id=session.get('user_id'), chat_id=int(chat_id))
        # ============音频识别返回结果============
        if audio_text:
            history_manager.add_message(HumanMessage(content=[file.filename for file in audio_files]))
            history_manager.add_message(AIMessage(content=audio_text))
            return jsonify({
                "response": audio_text,
                "conversation_id": chat_id,
                "new_conversation_created": False
            })
        # ============文生图============
        if text2img and text2img == "true":
            generate_image_ret_dict = generate_image(user_msg)
            logger.debug(f"文生图结果:{generate_image_ret_dict}")
            history_manager.add_message(HumanMessage(content=user_msg))
            history_manager.add_message(AIMessage(content=str(generate_image_ret_dict)))
            return jsonify({
                "image_url": generate_image_ret_dict["image_url"],
                "response": generate_image_ret_dict["description"],
                "conversation_id": chat_id,
                "new_conversation_created": False
            })
        # 这里的chat_id是前端传递的chat_id,不是根据用户id查找到
        ai_msg = rag_chatter.chat(
            user_id=user_id,
            chat_id=int(chat_id),
            user_question=user_msg + image_ai_msg,
            chain=rag_chatter.create_chain(
                rag_build.get_embedding_retriever(
                    redis_vector_store=rag_build.get_redis_vector_store_by_index_name(index_name)
                )
            ),
        )
        session["chat_id"] = chat_id
        return jsonify({
            "response": ai_msg,
            "conversation_id": chat_id,
            "new_conversation_created": False,
            "tips": tips
        })


# ------------------------------普通chat相关------------------------------
@app.route('/chat_page')
def chat_page():
    user_id = session.get("user_id")
    if not user_id:
        return redirect('/login')
    return render_template('chat.html')


@app.route('/chat/load_conversations', methods=['POST', 'GET'])
def chat_load_conversations():
    user_id = session.get('user_id', 0)  # 假设用户已登录，从 session 获取 user_id
    user_chat_sessions = find_chat_sessions_by_user_id(user_id=user_id)
    if user_chat_sessions:
        logger.debug(f"用户会话列表:{user_chat_sessions}")
        """# 构建返回值
        [
          {
            "id": 1,
            "title": "新对话"
          },
          {
            "id": 2,
            "title": "关于AI的问题"
          }
        ]
        """
        ret_list: list[dict] = []
        for user_chat_session in user_chat_sessions:
            if user_chat_session.chat_type == "normal":
                ret_list.append({
                    "id": user_chat_session.chat_id,
                    "title": user_chat_session.title
                })

        return jsonify(ret_list)
    return jsonify([])


@app.route('/chat/switch_conversation/<int:id>', methods=['GET'])
def chat_switch_conversation(id):
    if not id:
        return jsonify({"error": "Missing chat_id"}), 400
    # 将chat_id保存到session中，下次请求时使用
    session["chat_id"] = id
    # 这里的id就是chat_id也就是ai聊天模块中的session_id
    return jsonify(view_chat_history(user_id=session.get('user_id'), session_id=id))


@app.route('/chat/delete_conversation/<int:id>', methods=['GET'])
def chat_delete_conversation(id):
    if not id:
        return jsonify({"error": "Missing chat_id"}), 400
    # 将chat_id保存到session中，下次请求时使用
    session["chat_id"] = id
    try:
        # 这里的id就是chat_id也就是ai聊天模块中的session_id
        logger.debug(f"{clear_history(user_id=session.get('user_id'), session_id=int(id))}")
        if delete_chat_session(user_id=session.get('user_id'), chat_id=int(id)):
            logger.debug(f"删除会话成功:{id}")
            return jsonify({"success": True})
    except Exception as e:
        logger.error(e)
        return jsonify({"error": "Missing chat_id"}), 500


@app.route('/chat', methods=['POST', 'GET'])
def chat():
    audio_text = None  # 初始化音频转文字结果变量

    need_create_new_conversation = True
    # 用户发送的消息在前端叫做 prompt
    user_msg = request.form.get("prompt")
    # 使用的模型名称在前端叫做 model
    model_name = request.form.get("model")
    # 看看是否需要文生图
    text2img = request.form.get("enable_txt2img")
    # 当前用户的会话id在前端叫做 conversation_id,在数据库操作中叫做chat_id,在模型使用模块叫做session_id
    chat_id = request.form.get("conversation_id")
    # logger.debug(f"用户发送的消息:{user_msg}\t使用的模型名称:{model_name}\t当前用户的会话id:{chat_id}")
    # 这是前端发来的图片列表
    images = request.files.getlist("images")

    # ============音频转文字============
    # 获取前端发来的音频文件
    audio_files = request.files.getlist("audios")
    logger.debug(f"音频文件:{audio_files}")
    logger.debug(f"音频文件列表长度:{len(audio_files)}")
    if audio_files and len(audio_files) != 0:
        logger.debug(f"进入处理音频过程,如果不是上传的音频或者没有上传音频不应进入这里")

        try:
            # 计数器音频文件当前处理到第几个
            count_audio = 1
            audio_text = "以下是音频转录结果:"
            for audio in audio_files:
                audio_path = os.getcwd() + audio_to_text_relative_audio_path + str(
                    session.get('user_id')) + "/" + "audio_to_text/"
                logger.debug(f"audio_path:{audio_path}")
                # 如果audio目录不存在就创建
                if not os.path.exists(audio_path):
                    os.makedirs(audio_path)
                with open(audio_path + audio.filename, "wb") as f:
                    f.write(audio.read())
                logger.debug(f"处理音频文件路径:{audio_path + audio.filename}")
                audio_text += f"\n第{count_audio}个音频转录结果:"
                audio_text += audio_to_text(audio_path + audio.filename)
                count_audio += 1

        except Exception as e:
            logger.error(e)
        logger.debug(f"音频转录结果:{audio_text}")
    user_id = session.get('user_id', 0)
    # 如果没有从前端获取到chat_id(或者说获取到chat_id不是空)，则创建一个新的对话
    if chat_id:  # 表示有会话id,那么就不需要创建新的对话
        need_create_new_conversation = False
    # ============图片分析============
    image_ai_msg = str()
    if images and len(images) != 0:
        logger.debug(f"test image_name:{images[0].filename}")
        # 分析 图片
        image_ai_msg = image_analysis.analysis(images=images, upload_folder=image_analysis_upload_folder + "/" + str(
            session.get('user_id')) + "/" + "image_analysis/")
        if image_ai_msg is None:
            logger.debug("图片分析失败")
            return jsonify({'error': '分析图片失败'}), 400
    # ===========聊天逻辑处理,需要区分为有chat_id(从以前的历史继续对话)没有chat_id(新创建的对话)============
    if need_create_new_conversation:
        # 当前没有对话,新加一个对话
        """
        这段代码的可读性有点差,特别注释一下,当前需要获取一个新的chat_id;
        但是对于数据中的操作来说,想要得到chat_id需要先创建一个chat_session;
        而创建一个chat_session需要chat_id,那么我们通过根据user_id找到其所有的chat_session,之后
        找到其中的chat_id的最大值+1,如果是空列表说明当前用户没有对话,就返回0,之后我将其+1
        将用户输入的前20个字符作为title
        """
        chat_session = add_chat_session(
            user_id=user_id,
            chat_id=get_max_chat_id(
                user_chat_sessions=find_chat_sessions_by_user_id(
                    user_id=user_id
                )
            ) + 1,
            title=user_msg[:20]
        )
        logger.debug(f"创建的会话:chat_id:{chat_session.chat_id}\tuser_id:{chat_session.user_id}")
        history_manager = get_history(user_id=session.get('user_id'), session_id=chat_session.chat_id)
        # ============音频识别返回结果============
        if audio_text:
            history_manager.add_message(HumanMessage(content=[file.filename for file in audio_files]))
            history_manager.add_message(AIMessage(content=audio_text))
            return jsonify({
                "response": audio_text,
                "conversation_id": chat_session.chat_id,
                "new_conversation_created": True
            })
        # ============文生图============
        if text2img and text2img == "true":
            generate_image_ret_dict = generate_image(user_msg)
            logger.debug(f"文生图结果:{generate_image_ret_dict}")
            history_manager.add_message(HumanMessage(content=user_msg))
            history_manager.add_message(AIMessage(content=str(generate_image_ret_dict)))
            return jsonify({
                "image_url": generate_image_ret_dict["image_url"],
                "response": generate_image_ret_dict["description"],
                "conversation_id": chat_session.chat_id,
                "new_conversation_created": True
            })
        ai_msg = chat_with_user(user_question=user_msg + image_ai_msg, session_id=chat_session.chat_id, user_id=user_id)
        session["chat_id"] = chat_session.chat_id
        return jsonify({
            "response": ai_msg,
            "conversation_id": chat_session.chat_id,
            "new_conversation_created": True
        })
    else:
        history_manager = get_history(user_id=session.get('user_id'), session_id=int(chat_id))
        # ============音频识别返回结果============
        if audio_text:
            history_manager.add_message(HumanMessage(content=[file.filename for file in audio_files]))
            history_manager.add_message(AIMessage(content=audio_text))
            return jsonify({
                "response": audio_text,
                "conversation_id": chat_id,
                "new_conversation_created": False
            })
        # ============文生图============
        if text2img and text2img == "true":
            generate_image_ret_dict = generate_image(user_msg)
            logger.debug(f"文生图结果:{generate_image_ret_dict}")
            history_manager.add_message(HumanMessage(content=user_msg))
            history_manager.add_message(AIMessage(content=str(generate_image_ret_dict)))
            return jsonify({
                "image_url": generate_image_ret_dict["image_url"],
                "response": generate_image_ret_dict["description"],
                "conversation_id": chat_id,
                "new_conversation_created": False
            })
        # 这里的chat_id是前端传递的chat_id,不是根据用户id查找到
        ai_msg = chat_with_user(user_question=user_msg + image_ai_msg, session_id=int(chat_id), user_id=user_id)
        session["chat_id"] = chat_id
        return jsonify({
            "response": ai_msg,
            "conversation_id": chat_id,
            "new_conversation_created": False
        })


@app.route('/chat/send_message', methods=['POST'])
# ------------------------------admin相关------------------------------
@app.route('/admin')
def admin():
    if session.get("role") != "admin":
        return redirect('/')
    return render_template('admin.html')


@app.route('/admin/add/new_user', methods=['POST'])
def admin_add_user_process():
    data = request.get_json()
    if not data:
        logger.debug("数据为空")
        return jsonify({"state": "fail"})
    required_fields = ["user_mail", "user_name", "user_password"]
    if not all(field in data for field in required_fields):
        logger.debug("部分数据为空")
        return jsonify({"state": "fail"})
    user_mail = data["user_mail"]
    user_name = data["user_name"]
    user_password = data["user_password"]
    user_role = data["user_role"]
    logger.debug(f"用户信息:{user_mail}\t{user_name}\t{user_password}\t{user_role}")

    user = add_user(user_mail=user_mail, user_password=user_password, user_name=user_name)
    logger.debug(f"用户:{user}")
    logger.debug(f"用户id:{user.user_id}")
    user_role = add_user_role(user_id=user.user_id, role_id=2)
    if user_role:
        logger.debug(f"用户添加成功:{user_role}")
        return jsonify({"state": "success"})

    logger.debug(f"用户添加失败:{user_role}")
    return jsonify({"state": "fail"})


@app.route('/admin/search/all', methods=['POST', "GET"])
def admin_search_all():
    if session.get("role") != "admin":
        return redirect('/')
    users = find_all_user()

    if users:
        logger.debug(f"所有用户信息:{users}")
        return jsonify([{
            "user_id": user.user_id,
            "user_name": user.user_name,
            "user_mail": user.user_mail,
            "user_password": user.user_password,  # 注意：密码不应该明文传输，生产环境建议脱敏或加密
            "user_role": find_role_by_id(find_user_role_by_user_id(user.user_id).role_id).role_name  # 获取角色名称
        } for user in users])
    return jsonify({"state": "fail"})


@app.route('/admin/search/by_mail', methods=['POST'])
def admin_search_by_mail():
    data = request.get_json()
    user_mail = data["user_mail"]
    user_id = get_id_by_mail(user_mail)
    if user_id:
        user = find_user_by_id(user_id)
        if user:
            logger.debug(f"用户信息:{user.to_dict()}")
            return jsonify({
                "state": "success",
                "data": user.to_dict()
            })

    return jsonify({
        "state": "fail",
        "data": {
            "user_id": None,
            "user_mail": None,
            "user_name": None,
            "user_password": None,
            "user_role": None
        }
    })


@app.route('/admin/search/by_user_id', methods=['POST'])
def admin_search_by_user_id():
    data = request.get_json()
    user_id = data["user_id"]
    if user_id:
        user = find_user_by_id(user_id)
        if user:
            logger.debug(f"用户信息:{user.to_dict()}")
            return jsonify({
                "state": "success",
                "data": user.to_dict()
            })

    return jsonify({
        "state": "fail",
        "data": {
            "user_id": None,
            "user_mail": None,
            "user_name": None,
            "user_password": None,
            "user_role": None
        }
    })


@app.route('/admin/update/by_user_id', methods=['POST'])
def admin_update_by_user_id():
    data = request.get_json()
    user_id = data["user_id"]
    if user_id:
        user = update_user(user_id=user_id, user_name=data["user_name"], user_password=data["user_password"],
                           user_mail=data["user_mail"])
        if user:
            logger.debug(f"用户信息:{user.to_dict()}")
            return jsonify({
                "state": "success",
                "data": user.to_dict()
            })
    return jsonify({
        "state": "fail",
        "data": {
            "user_id": None,
            "user_mail": None,
            "user_name": None,
            "user_password": None,
            "user_role": None
        }
    })


@app.route('/admin/delete/by_user_id', methods=['POST'])
def admin_delete_by_user_id():
    data = request.get_json()
    user_id = data["user_id"]
    if user_id:
        user = delete_user(user_id)
        if user:
            logger.debug(f"用户信息:{user.to_dict()}")
            return jsonify({
                "state": "success",
                "data": user.to_dict()
            })
    return jsonify({
        "state": "fail",
        "data": {
            "user_id": None,
            "user_mail": None,
            "user_name": None,
            "user_password": None,
            "user_role": None
        }
    })


if __name__ == '__main__':
    logger.debug("测试进入app.run()")
    # with app.app_context():
    #     db.create_all()
    #     add_default_roles()
    # #     user_role = add_role("user")
    # #     logger.info(f"user_role: id:{user_role.role_id}\tname:{user_role.role_name}")

    app.run(host='0.0.0.0', port=5000, debug=True)
